package cn.wps.moffice.main.local.filebrowser.operator.fscache;

import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import android.annotation.SuppressLint;
import android.util.SparseArray;
import cn.wps.moffice.main.local.filebrowser.BrowserConst;
import cn.wps.moffice.main.local.filebrowser.dao.DirFileCacheModel;
import cn.wps.moffice.main.local.filebrowser.dao.Sear;

/**
 * 所有文档 本地目录 数据缓存中心. [单进程使用]
 *
 * @author wangxiaohua
 *
 */
public class DataCenter {
	// 目录缓存: 首次扫描 /加载 ; 所有文档退出 会调用.
	private HashMap<String, Long> mCacheDirPool = null;
	private Object mCacheDirPoolLock = new Object();

	// 深度扫描结果集 [首次启动 列表下拉].
	private SparseArray<HashSet<String>> mScanSetPool = null;
	private Object mScanLock = new Object();

	private int mScanSetPoolDirtyFlag = 0; // scan pool dirty flag

	// 是否完成了第一次seek
	private boolean mFirstSeekDone = false;

	//附加dirty index
//	public static int  CacheDirPoll_DirtyFlagIndex =  PublicConst.ALL_DOC_FILE_TYPE.length + 1;

	private static DataCenter DC = new DataCenter();;

	private DataCenter() {
		init();
		clearOldCache();
	}

	public static DataCenter getInstance() {
		return DC;
	}

	/*
	 * index 从 0 开始
	 */
	public static boolean isDirty(int flag, int index) {
		return (flag & (1 << index)) > 0;
	}

	public int getDirtFlag() {
		return mScanSetPoolDirtyFlag;
	}

	public void setDirty(int index, boolean isDirty) {
		if (isDirty) {
			mScanSetPoolDirtyFlag |= (1 << index);
		} else {
			mScanSetPoolDirtyFlag &= (Integer.MAX_VALUE^(1<<index));
		}
	}

	public void setDirtyAll() {
		mScanSetPoolDirtyFlag = Integer.MAX_VALUE;
	}

	public void clearDirtyAll() {
		mScanSetPoolDirtyFlag = 0;
	}

	private void clearOldCache() {
		Sear.clearOldAllCacheFileList();
	}
	
	private void init() {
		initScanSetPool();
	}

	private void initScanSetPool() {
		mScanSetPool = new SparseArray<HashSet<String>>();
		mCacheDirPool = new HashMap<String, Long>();
		mScanSetPool.put(BrowserConst.DOC_POSITION, new HashSet<String>());
		mScanSetPool.put(BrowserConst.PPT_POSITION, new HashSet<String>());
		mScanSetPool.put(BrowserConst.XSL_POSITION, new HashSet<String>());
		mScanSetPool.put(BrowserConst.PDF_POSITION, new HashSet<String>());
		mScanSetPool.put(BrowserConst.TXT_POSITION, new HashSet<String>());
		mScanSetPool.put(BrowserConst.OTHER_POSITION, new HashSet<String>());
	}

	/**
	 * 1. SeekType.onFresh SeekType.onScan 时, 向 scanSetPool 增加数据. 2.
	 * SeekType.onSeek 向 seekSetPool 增加数据.
	 */
	public boolean insertFile(File f, int index) {
		synchronized (mScanLock) {
			boolean rst = insert2Pool(mScanSetPool.get(index), f);
			if (rst) {
				setDirty(index, true);
				setDirty(BrowserConst.ALL_POSITION, true);
			}
			return rst;
		}
	}

	// 向指定的容器 增加文件路径.
	private boolean insert2Pool(HashSet<String> rs, File f) {
		return rs.add(f.getPath());
	}

	// 获取所有 深度搜索的 内存列表.
	@SuppressWarnings("unchecked")
	public SparseArray<HashSet<String>> getScanPool() {
		SparseArray<HashSet<String>> tmp = new SparseArray<HashSet<String>>();
		synchronized (mScanLock) {
			for (int i = 0; i < mScanSetPool.size(); i++) {
				int key = mScanSetPool.keyAt(i);
				HashSet<String> value = mScanSetPool.valueAt(i);
				synchronized (value) {
					tmp.put(key, (HashSet<String>) value.clone());
				}
			}
		}

		return tmp;
	}

	@SuppressWarnings("unchecked")
	public HashSet<String> getScanSet(int index) {
		synchronized (mScanLock) {
			if (BrowserConst.ALL_POSITION == index) {
				HashSet<String> result = new HashSet<String>();
				for (int i = 0; i < mScanSetPool.size(); i++) {
					int key = mScanSetPool.keyAt(i);
					if (key == BrowserConst.OTHER_POSITION) {
						continue;
					}
					HashSet<String> value = mScanSetPool.valueAt(i);
					result.addAll(value);
				}
				return result;
			} else {
				return (HashSet<String>) mScanSetPool.get(index).clone();
			}
		}
	}
	
	public int getScanSetSize(int index) {
		synchronized (mScanLock) {
			if (BrowserConst.ALL_POSITION == index) {
				int size = 0;
				for (int i = 0; i < mScanSetPool.size(); i++) {
					int key = mScanSetPool.keyAt(i);
					if (key == BrowserConst.OTHER_POSITION) {
						continue;
					}
					HashSet<String> value = mScanSetPool.valueAt(i);
					size += value.size();
				}
				return size;
			} else {
				return mScanSetPool.get(index).size();
			}
		}
	}

	public boolean removeItemInScanSet(int index, String path) {
		synchronized (mScanLock) {
			boolean rst = false;
			if (BrowserConst.ALL_POSITION == index) {
				for (int i = 0; i < mScanSetPool.size(); i++) {
					HashSet<String> value = mScanSetPool.valueAt(i);
					rst = value.remove(path);
					if (rst) {
						setDirty(BrowserConst.ALL_POSITION, true);
						break;
					}
				}
			} else {
				rst = mScanSetPool.get(index).remove(path);
				if (rst) {
					setDirty(index, true);
				}
			}
			return rst;
		}
	}

	/**
	 * 删除不存在的文件
	 */
	public boolean deleteUnExistScan() {
		boolean result = false;

		synchronized (mScanLock) {
			for (int i = 0; i < mScanSetPool.size(); i++) {
				int key = mScanSetPool.keyAt(i);
				HashSet<String> value = mScanSetPool.valueAt(i);
				HashSet<String> newScanSet = new HashSet<String>();
				for (String p : value) {
					if (new File(p).exists()) {
						newScanSet.add(p);
					} else {
						result = true;
					}
				}
				if (newScanSet.size() != value.size()) { //deleted some files set dirty
					setDirty(key, true);
					setDirty(BrowserConst.ALL_POSITION, true);
				}
				mScanSetPool.put(key, newScanSet);
			}
		}


		return result;
	}

	public void setFirstSeekDone() {
		mFirstSeekDone = true;
	}

	public boolean getFirstSeekDone() {
		return mFirstSeekDone;
	}

	// 获取目录缓存池.
	@SuppressWarnings("unchecked")
	public HashMap<String, Long> getCacheDirPool() {
		synchronized (mCacheDirPoolLock) {
			return (HashMap<String, Long>) mCacheDirPool.clone();
		}
	}

	public void insertCacheDirPool(String path, Long time) {
		synchronized (mCacheDirPoolLock) {
			mCacheDirPool.put(path, time);
		}
	}

	public void removeFromCacheDirPool(String path) {
		synchronized (mCacheDirPoolLock) {
			mCacheDirPool.remove(path);
		}
	}

	//===清空数据操作====
	private void resetScanPool() {
		if (null == mScanSetPool)
			return;

		synchronized (mScanLock) {
			for (int i = 0; i < mScanSetPool.size(); i++) {
				HashSet<String> value = mScanSetPool.valueAt(i);
				value.clear();
			}
		}
	}

	private void resetCacheDirPool() {
		if (null == mCacheDirPool)
			return;

		synchronized (mCacheDirPoolLock) {
			mCacheDirPool.clear();
		}
	}

	public void resetAllPool() {
		synchronized (mScanLock) {
			DC.resetScanPool();
			DC.resetCacheDirPool();
		}

		clearDirtyAll();
		mPersistentsLoaded = false; //标识位重新置回，下次读取持久化
	}

	// ======持久化相关============
	private boolean mPersistentsLoaded = false;

	/*
	 * 是否初始化load过
	 */
	public boolean getPersistentsLoaded() {
		return mPersistentsLoaded;
	}

	// 锁定整个对象
	@SuppressWarnings("unchecked")
	public synchronized boolean loadPersistents() {
		if (mPersistentsLoaded) {
			return true;
		}
		// 读取持久化
		DirFileCacheModel model = Sear.getAllCacheFileList();
		if (model != null) {
			if (model.mCacheDirPool == null || model.mScanSetPool == null) {
				return false;
			}

			if (model.mCacheDirPool.size() == 0 || model.mScanSetPool.size() == 0) {
				return false;
			}

			this.mCacheDirPool = model.mCacheDirPool;
			
			Iterator<Integer> iterator = model.mScanSetPool.keySet().iterator();
			while(iterator.hasNext()){
				Integer key = iterator.next();
				HashSet<String> value = model.mScanSetPool.get(key);
				synchronized (value) {
					mScanSetPool.put(key, (HashSet<String>) value.clone());
				}
			}
			
			setDirtyAll();  //设置所有类型数据变脏
			mPersistentsLoaded = true;
			return true;
		} else {
			return false;
		}
	}

	@SuppressLint("UseSparseArrays")
	@SuppressWarnings("unchecked")
	public synchronized void savePersistents() {
		DirFileCacheModel model = new DirFileCacheModel();
		model.mCacheDirPool = mCacheDirPool;

		HashMap<Integer, HashSet<String>> scanPool = new HashMap<Integer, HashSet<String>>();
		for (int i = 0; i < mScanSetPool.size(); i++) {
			int key = mScanSetPool.keyAt(i);
			HashSet<String> value = mScanSetPool.valueAt(i);
			synchronized (value) {
				scanPool.put(key, (HashSet<String>) value.clone());
			}
		}
		model.mScanSetPool = scanPool;
		Sear.saveAllCacheList(model);
	}
	// =======
}
